#ifndef DRAW_H
#define DRAW_H

#include "../source/cube.h"
#include <vector>
#include <string>
#include <cmath>

struct dVec
{
    double x, y, z;
    dVec(double x_ = 0., double y_ = 0., double z_ = 0.) :
        x(x_), y(y_), z(z_) {}
};

struct dCube
{
    double length, width, height, x, y, z;
    int cnt;
    dCube() {}
    dCube(double _length, double _width, double _height)
        : length(_length), width(_width), height(_height), cnt(0) {}
    dCube(double _length, double _width, double _height, double _x, double _y, double _z)
        : length(_length), width(_width), height(_height), x(_x), y(_y), z(_z), cnt(0) {}
    dCube(const Cube & c)
        : length(c.length), width(c.width), height(c.height), x(c.x), y(c.y), z(c.z), cnt(c.cnt) {}

    dCube & operator = (const Cube & o) {
        x = o.x, y = o.y, z = o.z;
        length = o.length, width = o.width, height = o.height;
        cnt = o.cnt;
        return *this;
    }
    
    double GetVolume()
    {
        return length * width * height;
    }
    
    void SetPos(double _x, double _y, double _z)
    {
        x = _x; y = _y; z = _z;
    }

    void rotate() {
        double zz = z; 
        z = y; y = x; x = zz;
        if (++cnt > 3) {
            std::swap(y, z); cnt = 0;
        }
    }

    bool operator < (const dCube & o) const {
        if (x != o.x) return x < o.x;
        if (y != o.y) return y < o.y;
        return z < o.z;
    }
};


class Draw
{
private:
    Draw() {}
    Draw(const Draw & a) {}

protected:
    static Draw e;
    static const double pi = 3.1415926;
    bool action_mode_, left_button_down_, frame_flag_;
    int display_num_;
    double l_, w_, h_, R_, theta_, oldmx_, oldmy_, z_, delta_x_;
    dVec w_point_, cur_view_point_;
    std::vector<dCube> cubes_;
    std::vector<dVec> color_;
    dCube frame_;

    void init();
    void DrawAllCubes();
    void DrawDisplayCubes();
    void DrawCube(const dCube &, dVec color);
    void DrawFrame();
    void FlyCube(const dCube &, dVec color);
    void SetViewpoint();
    void CalcViewpoint();
    void RefreshSight();
    void Redisplay(bool refresh = true);
    void BeginActionMode();
    void StopActionMode();
    bool PlaceNext();
    bool PlacePrevious();
    bool ActionMode() { return action_mode_; }
    void ProcessMove(int x, int y);
    double Radius() { return sqrt(1. * l_ * l_ + w_ * w_ + h_ * h_); }

    void SetCylinderPos(double R, double theta, double z)
        { R_ = R, theta_ = theta, z_ = z; }
    void SetMousePos(int x, int y);
    void SetLeftButtonDown() { left_button_down_ = true; }
    void SetLeftButtonUp() { left_button_down_ = false; }
    bool LeftButtonDown() { return left_button_down_; }
    void SwitchFrameFlag() { frame_flag_ = !frame_flag_; }

public:
    static Draw* Instance() { return &e; }
    ~Draw() {}
    void Main(int &, char **);
    void LoadCubes(const std::vector<Cube> &);
    void LoadCubes(const std::string &);
    static void keyboard(unsigned char key, int x, int y);
    static void mouse(int button, int state, int x, int y);
    static void display();
    static void reshape(int w, int h);
    static void mousemove(int x,int y);
};

#endif /* DRAW_H */